#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h> // file option
#include <signal.h>
#include <dirent.h>
#include <pthread.h>
// 进程通讯有管道，命名管道，信号，消息队列，信号量，共享内存，sock。
// 这里说命名管道，信号量。
// 命名管道，多个接收只会有一个会接收到数据，单次接收最大64K。它就是单向的。
// 信号
// sock是双向的，但是速度较慢；共享内存快；消息队列最大包8K，单向。根据实际情况定哪一种。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>   /* for signal */
#include <execinfo.h> /* for backtrace() */

/*
方式1，在打印时有函数位置。：
-------------------------------------------------
想要输出函数名，编译时需要加上 ： -g -rdynamic
使用 -Wl,-Map=test.map 获得编译信息。
--------------------------------------------------
运行时打印：
=========>>>catch signal 11 <<<=========
Dump stack start...
backtrace() returned 6 addresses
  [00] ./test(dump+0x32) [0x55ab6b00f37b]
  [01] ./test(signal_handler+0x36) [0x55ab6b00f48b]
  [02] /lib/x86_64-linux-gnu/libc.so.6(+0x43090) [0x7fd79918e090]
  [03] ./test(fifoThreadFunc+0x32) [0x55ab6b00f4e5]
  [04] /lib/x86_64-linux-gnu/libpthread.so.0(+0x8609) [0x7fd799345609]
  [05] /lib/x86_64-linux-gnu/libc.so.6(clone+0x43) [0x7fd79926a353]
Dump stack end...
--------------------------------------------------
可以看到是函数：fifoThreadFunc崩溃。找到fifoThreadFunc对应的位置。
cat test.map | grep fifoThreadFunc
                0x00000000000014b3                fifoThreadFunc
fifoThreadFunc的位置是0x00000000000014b3，崩溃位置是fifoThreadFunc+0x32。
--------------------------------------------------
使用命令addr2line找到具体哪一行！
addr2line 0x00000000000014e5 -e test -f
fifoThreadFunc
/home/lxin/workdir/testdir/git/clearnpc/clpc/clearn.v4/clearn.v4.009.02.signal/cSingal.c:99
*/
/*
方式2， 直接用addr2line得到位置：
-------------------------------------------------
编译时需要加上 ： -g
--------------------------------------------------
运行时打印：
=============>code happen crash signal = 11
Dump stack start...
backtrace() returned 5 addresses
  [00] ./test(+0x13a6) [0x555832b743a6]
  [01] /lib/x86_64-linux-gnu/libc.so.6(+0x43090) [0x7f8b1ccdc090]
  [02] ./test(+0x14dd) [0x555832b744dd]
  [03] /lib/x86_64-linux-gnu/libpthread.so.0(+0x8609) [0x7f8b1ce93609]
  [04] /lib/x86_64-linux-gnu/libc.so.6(clone+0x43) [0x7f8b1cdb8353]
Dump stack end...
--------------------------------------------------
使用命令addr2line找到具体哪一行！
addr2line 0x14dd -e test -f
可以得到dump函数
fifoThreadFunc
/home/lxin/workdir/testdir/git/clearnpc/clpc/clearn.v4/clearn.v4.009.02.signal/cSingal.c:117
*/

#define CODE_CRASH_CHECK 3

void signal_handler(int signo)
{
#if 0
    char buff[64] = {0x00};
    sprintf(buff, "cat /proc/%d/maps", getpid());
    system((const char *)buff);
#endif
#define BACKTRACE_SIZE 32
    int j, nptrs;
    void *buffer[BACKTRACE_SIZE];
    char **strings;
    printf("=============>code happen crash signal = %d\n", signo);
    printf("Dump stack start...\n");
    nptrs = backtrace(buffer, BACKTRACE_SIZE);
    printf("backtrace() returned %d addresses\n", nptrs);
    strings = backtrace_symbols(buffer, nptrs);
    if (strings == NULL)
    {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }
    for (j = 0; j < nptrs; j++)
    {
        printf("  [%02d] %s\n", j, strings[j]);
    }
    free(strings);

    printf("Dump stack end...\n");
    signal(signo, SIG_DFL); /* 恢复信号默认处理 */
    raise(signo);           /* 重新发送信号 */
}
void *fifoThreadFunc(void *ptr)
{
    printf("thread begin\n");
    sleep(1);
#if CODE_CRASH_CHECK == 0
    char *tmpptr = NULL;
    // 0地址，读也会导致崩溃！被SIGSEGV捕获
    printf("ptr 0 data=%d\n", tmpptr[0]);
#endif
    printf("thread end\n");
    return NULL;
}
#define FIFO_MAX_LEN (200 * 1024)
int main()
{
    pthread_t tmpthread;
    signal(SIGINT, signal_handler);
    signal(SIGSEGV, signal_handler);
    signal(SIGBUS, signal_handler);
    signal(SIGABRT, signal_handler);
    signal(SIGFPE, signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGTRAP, signal_handler);
    signal(SIGPIPE, signal_handler);
    pthread_create(&tmpthread, NULL, fifoThreadFunc, NULL);
    printf("main begin\n");
#if CODE_CRASH_CHECK == 1
    char *tmpptr = (char *)malloc(10);
    free(tmpptr);
    // SIGABRT 捕获
    free(tmpptr);
#endif
#if CODE_CRASH_CHECK == 2
    int div = 0;
    // SIGFPE 捕获
    int tmpval = 100 / div;
    printf("div finish:%d\n", tmpval);
#endif
#if CODE_CRASH_CHECK == 3
    // SIGSEGV 捕获
    printf("printf error:%s\n", 1234);
#endif
    usleep(1000 * 1000);
    pthread_join(tmpthread, NULL);
    printf("main quit\n");
    return 0;
}
